<?php
//-------------------------------------------------------------------------
// OVIDENTIA http://www.ovidentia.org
// Ovidentia is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2, or (at your option)
// any later version.
// 
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
// USA.
//-------------------------------------------------------------------------
/**
 * @license http://opensource.org/licenses/gpl-license.php GNU General Public License (GPL)
 * @copyright Copyright (c) 2006 by CANTICO ({@link http://www.cantico.fr})
 */
//include_once 'base.php';
require_once $GLOBALS['babInstallPath'] . '/addons/widgets/widgets/assert.php';
require_once $GLOBALS['babInstallPath'] . '/addons/widgets/widgets/canvas.class.php';

//require_once $GLOBALS['babInstallPath'] . 'utilit/devtools.php';






/**
 * The Widget_Displayable_Interface denotes objects that can be displayed on a Widget_Canvas.
 * 
 * @package GUI
 */
interface Widget_Displayable_Interface
{
	/**
	 * @param Widget_Canvas	$canvas		The canvas 
	 * @return	string		The rendered string corresponding to the object on the specified canvas.
	 */
	public function display(Widget_Canvas $canvas);
}



/**
 * Insert an array at a specified position in another array.
 * if $lengthToReplace is specified and greater than zero this number
 * of elements will be removed from the orginal array.
 *
 * Requires PHP 5.0.2 + (to preserve array keys)
 * 
 * @param array		$destArray
 * @param array		$arrayToInsert
 * @param int		$insertPosition
 * @param int		$lengthToReplace
 * @return array
 */
function Widget_arrayInsert($destArray, $arrayToInsert, $insertPosition, $lengthToReplace = 0)
{
	$arrayBeginning = array_slice($destArray, 0, $insertPosition, true);
	$arrayEnding = array_slice($destArray, $insertPosition + $lengthToReplace, count($destArray) - ($insertPosition + $lengthToReplace), true);
	
	$destArray = $arrayBeginning + $arrayToInsert + $arrayEnding;
	
	return $destArray;
}

/**
 * Appends an array to another array.
 *
 * Preserves array keys.
 * 
 * @param array		$destArray
 * @param array		$arrayToAppend
 * @return array
 */
function Widget_arrayAppend($destArray, $arrayToAppend)
{
	$destArray = $destArray + $arrayToAppend;

	return $destArray;
}



class Widget_SizePolicy {
	const IGNORED =	'ignored'; 	
	const MINIMUM =	'minimum';
	const MAXIMUM =	'maximum';
	const FIXED =	'fixed'; 	
}


/**
 * @package GUI
 * @return Widget_Item
 */
function Widget_Item($id)
{
	return Widget_Item::getById($id);
}


/**
 * Widget_Item is the base class for {@link Widget_Widget} and {@link Widget_Layout}.
 * They represent the objects that can be placed in a layout.
 *
 * Items have a unique id (on a specific page) and can be retrieved from any
 * place in the code using the static method Widget_Item::{@link getById}.
 * 
 * @package GUI
 */
abstract class Widget_Item
{
	private $_id;
	
	/**
	 * @var array $_classes		Additional (html) classes.
	 */
	private $_classes;

	/**
	 * @var Widget_Item $_parent
	 */
	private $_parent;

	private $_title;

	private $_metadata;

	
	protected $_sizePolicy = '';
	protected $_sizeHint;
	
	/**
	 * @var Widget_CanvasOptions $_canvasOptions
	 */
	protected $_canvasOptions = null;

	/**
	 * All items ID of objects inherited from Widget_Item
	 */
	private static $_all_items = array();
	
	/**
	 * All class name of objects inherited from Widget_Item
	 */
	protected static $_all_classes = array();
	
	/**
	 * The specified id must be unique for all items created on the page.
	 * If id is not specified, a unique id is automatically generated.
	 * 
	 * @param string $id	The item unique id.
	 * @return Widget_Item
	 */
	public function __construct($id = null)
	{
		// The itemCounter is used to generate unique ids.
		static $itemCounter = 1;
		if (is_null($id)) {
			$id = strtolower(get_class($this)) . $itemCounter++;
		}
		$this->setId($id);
		$this->setParent(null);
		$this->_initialized = false;
		$this->_title = null;
		$this->_classes = array();
		$this->_metadata = array();
		
		$this->addAllClasses();
//		self::$_all_classes[$class] = $class;
	}


	/**
	 * Updates the static $_all_classes array.
	 */
	protected function addAllClasses()
	{
		$classname = get_class($this);
		if (array_key_exists($classname, self::$_all_classes)) {
			return;
		}
		
		$obj = $this;
		self::$_all_classes[$classname] = $classname;
		
		while ($classname = get_parent_class($classname)) {
			if (array_key_exists($classname, self::$_all_classes)) {
				return;
			}
			self::$_all_classes[$classname] = $classname;
		}
		
		
	}


	/**
	 * 
	 * @return Widget_CanvasOptions
	 */
	static public function Options()
	{
		require_once dirname(__FILE__).'/canvasoptions.class.php';
		return new Widget_CanvasOptions();
	}

	/**
	 * Sets the canvas options of the item.
	 *
	 * @param Widget_CanvasOptions $canvasOptions
	 * @return Widget_Widget
	 */
	function setCanvasOptions(Widget_CanvasOptions $canvasOptions)
	{
		$this->_canvasOptions = $canvasOptions;
		return $this;
	}
	
	/**
	 * @return Widget_CanvasOptions|null
	 */
	function getCanvasOptions()
	{
		return $this->_canvasOptions;
	}
	
	/**
	 * Sets the size policy of the item.
	 * 
	 * @see Widget_SizePolicy
	 *
	 * @param string $policy
	 * @return Widget_Widget
	 */
	function setSizePolicy($policy)
	{
		$this->_sizePolicy = $policy;
		return $this;
	}
	
	/**
	 * Returns the size policy of the item.
	 * 
	 * @see Widget_SizePolicy
	 * @return string | null
	 */
	function getSizePolicy()
	{
		return $this->_sizePolicy;
	}
	
	
	/**
	 * Sets the parent of the item.
	 *
	 * @param Widget_Item $parent
	 */
	public function setParent($parent)
	{
		$this->_parent = $parent;
	}


	/**
	 * Returns the parent of the item.
	 *
	 * @return Widget_Item A reference to the parent item or null.
	 */
	public function getParent()
	{
		return $this->_parent;
	}
	
	/**
	 * Returns the item with the specified id or null.
	 *
	 * @param string	$id		The id of the item to retrieve
	 * @return Widget_Item
	 */
	static public function getById($id)
	{
		assert('is_string($id); /* The "id" parameter must be a string */');
		if (isset(Widget_Item::$_all_items[$id]))
		{
			return Widget_Item::$_all_items[$id];
		}
		return null;
	}


	/**
	 * Returns the item with the specified id or null.
	 * 
	 * @param string	$id		The id of the item to retrieve
	 * @return Widget_Item
	 */
	static public function _($id)
	{
		return Widget_Item::getById($id);
	}


	/**
	 * Sets the id of the item.
	 * 
	 * The id must be unique for all items created on the page.
	 *
	 * @param string $id
	 */
	public function setId($id)
	{
		assert('is_string($id); /* The "id" parameter must be a string */');
		assert('!isset(Widget_Item::$_all_items[$id]); /* An item with the id "' . $id . '" already exists */');
		if (isset($this->_id)) {
			unset(Widget_Item::$_all_items[$this->_id]);
		}
		Widget_Item::$_all_items[$id] =& $this;
		$this->_id = $id;
		
		return $this;
	}


	/**
	 * Returns the item id.
	 *
	 * @return string
	 */
	public function getId()
	{
		return $this->_id;
	}

	/**
	 * @return Widget_Item
	 */
	public function addClass($className)
	{
		$this->_classes[] = $className;
		return $this;
	}

	/**
	 * Returns the (style) classes associated to this item.
	 *
	 * @return array
	 */
	public function getClasses()
	{
		return $this->_classes;
	}

	
	/**
	 * 
	 * @param int $size
	 * @param string $labelPosition		'top' or 'left'
	 * 
	 * @return Widget_Item
	 */
	public function setIconFormat($size, $labelPosition)
	{
		$this->addClass('icon-' . $labelPosition . '-' . $size . ' icon-' . $labelPosition . ' icon-' . $size . 'x' . $size);
		return $this;
	}


	/**
	 * Sets the title of the item.
	 *
	 * The title of the widget will be displayed in a tooltip.
	 * This method returns the widget itself so that other methods can be chained.
	 *
	 * @param string $title
	 * @return Widget_Item
	 */
	public function setTitle($title)
	{
		assert('is_string($title); /* The "title" parameter must be a string. */');
		$this->_title = $title;
		return $this;
	}

	/**
	 * Returns the item title.
	 *
	 * @return string
	 */
	public function getTitle()
	{
		return $this->_title;
	}


	


	public function dump($prefix = '')
	{
		$dumpString = $prefix . '&#9474;' . "\n" . $prefix . '&#9500;&#9472;&#9472;&#9472;' . get_class($this) . '("<b>' . $this->getId() . '</b>") ';
		
		
		
		return $dumpString;
	}



	/**
	 * Returns a string containing the html class of the item.
	 * 
	 * The html class is obtained by concatenating the class name of the item
	 * with its ancestors class names. (eg. "Widget_Frame Widget_ContainerWidget Widget_Widget Widget_Item").
	 * 
	 * @return string 	The html class of the item.
	 */
	protected function getHtmlClass()
	{
		$htmlclass = $classname = get_class($this);
		while ($classname = get_parent_class($classname)) {
			$htmlclass .= ' ' . $classname;
		}
		if (count($this->_classes) > 0) {
			$htmlclass .= ' ' . implode(' ', $this->_classes);
		}
		return $htmlclass;
	}


	/**
	 * Returns the html id of the item.
	 * 
	 * @return string	The html id of the item.
	 */
	protected function getHtmlId()
	{
		return htmlspecialchars($this->_id);
	}

	
	/**
	 * add a metadata on item
	 * @param	string		$key
	 * @param	string		$value
	 * @return	Widget_Item
	 */
	public function setMetadata($key, $value) {
	
		$this->_metadata[$key] = $value;
		return $this;
	}

	/**
	 * get metadata
	 * key is optional, without key all metadata are returned as array
	 * @param	string	$key
	 *
	 * @return null|string|array
	 */
	public function getMetadata($key = null) {
		if (null === $key) {
			return $this->_metadata;
		} elseif (isset($this->_metadata[$key])) {
			return $this->_metadata[$key];
		} else {
			return null;
		}
	
	}

	/**
	 * Set a confirmation message usable in canvas for the click event
	 * @param	string	$message
	 * @return Widget_Item
	 */
	public function setConfirmationMessage($message) {
		$this->setMetadata('confirmationMessage', $message);
		$this->addClass('widget-confirm');
		return $this;
	}
}
